
var cp = require('child_process')
const Model = require('../dbs/model/getCollection.js')
const LocationSchema = require('../dbs/schema/locationSchema.js')
const StudentRelationSchema = require('../dbs/schema/studentRelationSchema.js')
const ProcessHistorySchema = require('../dbs/schema/processHistorySchema.js')
const SecurityPointSchema = require('../dbs/schema/securityPointSchema.js')
const fenceService = require('./fenceService.js')
const log = require('../com/logConfig.js')
const result = require('../com/result.js')
const util = require('../com/util.js')

/**
 * 存学生位置信息 
 * @param {*} location 
 */
let locationSave = async (location) => {
    let data = JSON.parse(location);
    let studentId = data.Student.id;
    let schoolList = [];
    let StudentModel = await Model.getComModel({
        dataBase: 'com_info',
        tableName: 'student_relation',
        schema: StudentRelationSchema
    });

    //处理学生人物关系数据
    if (data.studentRelation) {
        data.studentRelation.studentId = studentId;
        data.studentRelation.schoolList.map((val, index) => {
            val.idCopy = val.id;
            val.id = val.orgCode;
            return val;
        });
        data.studentRelation.parentList.map((val, index) => {
            val.parentTel = String(val.parentTel);
            return val;
        });
        data.studentRelation.teacherList.map((val, index) => {
            val.tel = String(val.tel);
            return val;
        });
        data.studentRelation.classList.map((val, index) => {
            val.classSerialNumber = String(val.classSerialNumber);
            return val;
        });
        schoolList = JSON.parse(JSON.stringify(data.studentRelation.schoolList));
        try {
            StudentModel
                .updateOne(
                    { 'studentId': studentId },
                    data.studentRelation,
                    { upsert: true }
                )
                .exec((err, doc) => { });
        } catch (e) { log.error('保存学生人物关系数据异常', e) }
    } else {
        schoolList = await new Promise((res, rej) => {
            StudentModel.findOne({ 'studentId': studentId }, async (err, doc) => {
                return res(doc.schoolList);
            });
        });
    }

    //处理电子围栏报警
    if (data.Gps && data.Gps[0] && data.Gps[0].Latitude) {
        cp.fork(__dirname + '/handFenceByLocation.js').send({ data: data, globalConfig: global.COM_CONFIG });
    }

    delete data.studentRelation;
    //向学生所处所有学校存该学生位置信息
    for (let i = 0; i < schoolList.length; i++) {
        let schoolId = schoolList[i].id;
        let SchoolModel = await Model.getSchoolModel({
            schoolId: schoolId,
            studentId: studentId,
            schema: LocationSchema
        });
        // 插入数据
        await new Promise((res, rej) => {
            new SchoolModel(data).save((err, doc) => {
                return res();
            });
        });
        //处理是否sos校徽报警
        handleSos(location, schoolList[i], SchoolModel);
    }

    return;
};

/**
 * 根据学生id去查学生所有的人物关系
 * @param {}} ctx 
 * @param {*} next 
 */
let getAll = async (ctx, next) => {
    let query = ctx.query;
    let StudentModel = await Model.getComModel({
        dataBase: 'com_info',
        tableName: 'student_relation',
        schema: StudentRelationSchema
    });
    return await new Promise((res, rej) => {
        StudentModel.findOne({ 'studentId': query.id }, async (err, doc) => {
            ctx.body = result.go(result.code.CODE_200, doc);
            return res();
        });
    });
};

/**
 * 根据学校id(可选)和学生id查学生最新位置数据
 */
let getStudentLocation = async (ctx, next) => {

    let param = ctx.request.body;
    //学校id
    let schoolId = param.schoolId;
    //许多学生的ids
    let studentIds = JSON.parse(param.studentIds);
    //需要查几条数据 - 默认3条
    let limit = param.limit ? param.limit : 3;
    //要查询的列
    let column = param.column ? JSON.parse(param.column) : { Time: 1, Gps: 1 };
    //查询所带的条件  要根据时间段和Gps不为空来查
    let where = param.where ? JSON.parse(param.where) : {};

    let arr = [];
    let count = 0;

    if (!schoolId) {
        //查学校id
        let StudentRelationModel = await Model.getComModel({
            dataBase: 'com_info',
            tableName: 'student_relation',
            schema: StudentRelationSchema
        });
        schoolId = await new Promise((res, rej) => {
            StudentRelationModel
                .findOne({ 'studentId': studentIds[0] }, { schoolList: 1 })
                .exec((error, doc) => {
                    return res(doc.schoolList[0].id);
                });
        });
    }

    return await new Promise(async (res, rej) => {
        for (let i = 0; i < studentIds.length; i++) {
            let SchoolModel = await Model.getSchoolModel({
                schoolId: schoolId,
                studentId: studentIds[i],
                schema: LocationSchema
            });
            SchoolModel
                .find(where, column)
                .limit(parseInt(limit))
                .sort({ Time: -1 })
                .exec((error, doc) => {
                    doc.StudentId = studentIds[i];
                    arr.push(doc);
                    if (++count == studentIds.length) {
                        ctx.body = result.go(result.code.CODE_200, arr);
                        return res();
                    }
                });
        }
    });
};

/**
 * 查学生位置信息 - 过滤空Gps - 每个学生只查最近的一条
 */
let getLocationNNEmpty = async (ctx, next) => {
    let param = ctx.request.body;

    //学校ids
    let schools = param.schools;

    let len = 0;
    let resGo = [];
    let count = 0;

    return await new Promise(async (res, rej) => {
        for (let i = 0; i < schools.length; i++) {
            for (let j = 0; j < schools[i].students.length; j++) {
                len++;
                let orgCode = schools[i].orgCode;
                let studentId = schools[i].students[j];
                let SchoolModel = await Model.getSchoolModel({
                    schoolId: orgCode,
                    studentId: studentId,
                    schema: LocationSchema
                });
                SchoolModel
                    .find({ 'Gps.Longitude': { $exists: true } })
                    .limit(1)
                    .sort({ Time: -1 })
                    .exec((error, doc) => {
                        if (!doc[0] || !doc[0].Gps) {
                            ++count;
                            if (count == len) {
                                ctx.body = result.go(result.code.CODE_200, resGo);
                                return res();
                            }
                        } else {
                            SchoolModel
                                .find({ 'Send-Type': 'T166' })
                                .limit(1)
                                .sort({ Time: -1 })
                                .exec((error2, doc2) => {
                                    ++count;
                                    if (doc2[0]) {
                                        let reDoc = JSON.parse(JSON.stringify(doc2[0]));
                                        reDoc.orgCode = orgCode;
                                        reDoc.Gps = doc[0].Gps[0];
                                        reDoc.studentId = studentId;
                                        let disS = util._timeDiff(reDoc.Time, Date.now());
                                        reDoc.onLine = disS > global.COM_CONFIG.onLineDis ? false : true;
                                        reDoc.configDis = global.COM_CONFIG.onLineDis;
                                        reDoc.nowDis = disS;
                                        resGo.push(util._delOthLocation(reDoc));
                                    }
                                    if (count == len) {
                                        ctx.body = result.go(result.code.CODE_200, resGo);
                                        return res();
                                    }
                                });
                        }
                    });
            }
        }
    });
};

/**
 * 根据学校id(可选)和学生id查学生一段时间的轨迹-
 */
let getStuOrbit = async (ctx, next) => {
    let headerUser = JSON.parse(ctx.headers['authorization-user']);
    let param = ctx.query;
    //学校id/学生id-
    //let schoolId = headerUser.orgId;
    let schoolId = '500107001';
    let studentId = param.studentId;
    if (!studentId) {
        ctx.body = result.go(result.code.CODE_501);
        return;
    }

    if (!schoolId) {
        //查学校id
        let StudentRelationModel = await Model.getComModel({
            dataBase: 'com_info',
            tableName: 'student_relation',
            schema: StudentRelationSchema
        });
        schoolId = await new Promise((res, rej) => {
            StudentRelationModel
                .findOne({ 'studentId': studentId }, { schoolList: 1 })
                .exec((error, doc) => {
                    let id = null;
                    if (doc) {
                        id = doc.schoolList[0].id
                    }
                    return res(id);
                });
        });
    }
    if (!schoolId) {
        ctx.body = result.go(result.code.CODE_501);
        return;
    }

    let nowD = Date.now();
    let s = String(nowD).length > 10 ? 1 : 1000;

    let where = {
        'Gps.Longitude': {
            '$exists': true
        },
        'Time': {
            //默认查轨迹是3天前到现在- 
            $gte: new Date((nowD * s) - global.COM_CONFIG.stuOrbitS),
            $lt: new Date(nowD * s)
        }
    };
    if (param.startTime) {
        //数据库的时间大于等于这个时间
        let i = String(param.startTime).length > 10 ? 1 : 1000;
        let timeNum = parseInt(param.startTime, 10) * i;
        where['Time']['$gte'] = new Date(timeNum);
    }
    if (param.endTime) {
        //数据库的时间小于这个时间-
        let i = String(param.endTime).length > 10 ? 1 : 1000;
        let timeNum = parseInt(param.endTime, 10) * i;
        where['Time']['$lt'] = new Date(timeNum);
    }
    return await new Promise(async (res, rej) => {
        let SchoolModel = await Model.getSchoolModel({
            schoolId: schoolId,
            studentId: studentId,
            schema: LocationSchema
        });
        SchoolModel
            .find(where, { 'Gps': 1, 'Time': 1 })
            .exec((error, doc) => {
                ctx.body = result.go(result.code.CODE_200, doc);
                return res();
            });
    });
};

/**
 * 处理学生位置信息 - 判断是否需要报警
 * @param {*} location 
 */
let handleSos = async (location, school, SchoolModel) => {
    let data = JSON.parse(location);
    if (String(data['Sos-Sign']) == '1') {
        //sos一键报警
        let url = global.COM_CONFIG.activitiService.sosAlarm;
        data.schoolId = school.id;
        data.orgCode = school.orgCode;

        //得到学生最近的Gps信息
        SchoolModel
            .find({ 'Gps.Longitude': { $exists: true } })
            .sort({ Time: -1 })
            .limit(1)
            .exec(async (error, doc) => {
                if (doc[0]) {
                    data.distance = parseInt(util._getDisance(school.latitude, school.longitude, doc[0].Gps[0].Latitude, doc[0].Gps[0].Longitude));
                    delete data.studentRelation;
                    for (let i = 0; i < doc[0].Gps.length; i++) {
                        if (doc[0].Gps[i].Longitude) {
                            data['Gps'] = [doc[0].Gps[i]];
                            break;
                        }
                    }
                    //判断是否是校内
                    let sosSite = await fenceService.judgeSchoolFence({
                        schoolId: data.schoolId,
                        coordinate: [Number(data['Gps'][0].Longitude), Number(data['Gps'][0].Latitude)]
                    });
                    data.sosSite = sosSite ? 'in' : 'out';
                    //data.sosSite = 'in';
                    let realData = util._delOthLocation(data);
                    global.COM_CONFIG.post({
                        url: url,
                        data: JSON.stringify(realData)
                    });
                }
            });
    }
}

/**
 * 校徽报警 - 查离学生最近的相关人员安排任务
 */
let getSosCandidate = async (ctx, next) => {
    let param = ctx.request.body;
    //报警类型 - sos-security:校徽报警   pillar-alarm:报警柱报警     fire-alarm:火灾报警
    let chartType = param.chartType;
    //需要返回的候选人数量
    let candidateCount = parseInt(param.candidateCount);
    //学校id
    let schoolId = param.schoolId;
    //流程图设置的处理sos报警的组织
    let trsArr = param.trsArr;
    //报警地点的经纬度
    let studentLat, studentLon;
    if (chartType == 'sos-security') {
        //学生id
        let studentId = param.studentId;
        //查询学生最新位置
        let SchoolModel = await Model.getSchoolModel({
            schoolId: schoolId,
            studentId: studentId,
            schema: LocationSchema
        });
        let studentLocation = await new Promise((r1, j1) => {
            SchoolModel
                .find({ 'Gps.Longitude': { $exists: true } })
                .limit(1)
                .sort({ Time: -1 })
                .exec((error2, doc) => {
                    return r1(doc);
                });
        });
        studentLat = studentLocation[0].Gps[0].Latitude;
        studentLon = studentLocation[0].Gps[0].Longitude;
    } else if (chartType == 'pillar-alarm' || chartType == 'fire-alarm') {
        let alarmInfo = JSON.parse(param.alarmInfo);
        studentLat = alarmInfo.latitude;
        studentLon = alarmInfo.longitude;
    }

    //所有的人员的位置数据在这里面
    let allocation = [];
    //得到此学校填入的所有组织所有的人员信息
    let allRule = {};
    let len = 0;
    for (let trsKey in trsArr) {
        let result = await global.COM_CONFIG.post({
            url: global.COM_CONFIG.activitiService.getAllRoleInfo,
            data: JSON.stringify({ orgId: schoolId, roleList: [trsArr[trsKey]] })
        });
        try {
            allRule[trsArr[trsKey]] = JSON.parse(result).data;
        } catch (e) {
            allRule[trsArr[trsKey]] = [];
        }
        len += allRule[trsArr[trsKey]].length;
    }

    await new Promise(async (r, j) => {
        let count = 0;
        //根据人员查位置信息
        for (let key in trsArr) {
            let trsVal = trsArr[key];
            switch (trsVal) {
                //查保安组织的所有位置信息
                case 'CODE_SECURITY':
                    let seArr = allRule['CODE_SECURITY'];
                    //保安组织的数据连接
                    let SecurityPointModel = await Model.getComModel({
                        dataBase: 'com_info',
                        tableName: 'security_point',
                        schema: SecurityPointSchema
                    });
                    for (let i = 0; i < seArr.length; i++) {
                        let pId = seArr[i];
                        SecurityPointModel
                            .find({
                                'orgCode': schoolId,
                                'phone': pId,
                                'data.location.longitude': { $exists: true }
                            })
                            .sort({ time: -1 })
                            .limit(1)
                            .exec((error, doc) => {
                                count++;
                                try {
                                    if (doc[0] && doc[0].data.location.longitude) {
                                        allocation.push({
                                            name: doc[0].data.user.username,
                                            peopleType: 'CODE_SECURITY',
                                            id: doc[0].phone,
                                            distance: util._getDisance(
                                                studentLat,
                                                studentLon,
                                                doc[0].data.location.latitude,
                                                doc[0].data.location.longitude,
                                            )
                                        });
                                    }
                                } catch (e) { }
                                if (count == len) {
                                    return r();
                                }
                            });
                    }
                    break;
                default:
                    break;
            }
        }
        if (count == len) {
            return r();
        }
    });

    //取位置排序最近
    allocation.sort((v1, v2) => {
        return v1.distance - v2.distance;
    });

    //返回的时候[{人员id,人员名字,人员所属组织}]
    //  [
    //             { name: '保安张三', peopleType: 'baoan', id: '10' },
    //             { name: '保安李四', peopleType: 'baoan', id: '12' },
    //             { name: '保安王麻子', peopleType: 'baoan', id: '14' }
    //         ]

    ctx.body = result.go(result.code.CODE_200, allocation.slice(0, candidateCount));

    return;
}

/**
 * 推送消息给家长阶段保存流程图和人物关系细节数据 - 以后所有的报警记录就可以自由的追溯
 * @param {*} ctx 
 * @param {*} next 
 */
let saveProcess = async (ctx, next) => {
    let data = JSON.parse(ctx.request.body.data);

    let ProcessHistoryModel = await Model.getComModel({
        dataBase: 'com_info',
        tableName: 'process_history',
        schema: ProcessHistorySchema
    });
    for (let key in data) {
        if (data[key].instanceYes) {
            data[key].overTime = new Date();
        }
        try {
            let noticeTissue = data[key].instanceInfo.noticeTissue;
            let candidateLeaders = data[key].instanceInfo.candidateLeaders;
            if (noticeTissue) {
                data[key].instanceInfo.noticeTissue = {
                    time: String(Date.now()),
                    tissue: noticeTissue
                };
            }
            if (candidateLeaders) {
                data[key].instanceInfo.candidateLeaders = {
                    time: String(Date.now()),
                    leader: JSON.parse(candidateLeaders)
                };
            }
        } catch (e) { }
        new ProcessHistoryModel(data[key]).save();
    }

    ctx.body = result.go(result.code.CODE_200);
    return;
}

/**
 * 分配任务给保安作为候选人阶段保存流程图和人物关系细节数据 - 以后所有的报警记录就可以自由的追溯
 */
let saveProcessAtAssign = async (ctx, next) => {
    let people = JSON.parse(ctx.request.body.people);
    let instanceInfo = JSON.parse(ctx.request.body.instanceInfo);

    let ProcessHistoryModel = await Model.getComModel({
        dataBase: 'com_info',
        tableName: 'process_history',
        schema: ProcessHistorySchema
    });

    let where = {
        instanceId: people[0].instanceId
    };

    //查询历史信息
    let insOne = await new Promise((res, rej) => {
        ProcessHistoryModel
            .findOne(where)
            .exec((error, doc) => {
                return res(doc);
            });
    });

    //先保存作为候选人的保安
    let peoLen = people.length - 1;
    await new Promise((res, rej) => {
        for (let key in people) {
            new ProcessHistoryModel(people[key]).save((error, doc) => {
                if (key == peoLen) {
                    return res();
                }
            });
        }
    });

    //同步所有数据
    let newInstanceInfo = insOne.instanceInfo;
    //分配任务阶段组装数据
    newInstanceInfo['candidateSecurity'] = {
        time: String(Date.now()),
        securities: instanceInfo
    };
    let newData = {
        createTime: insOne.createTime,
        instanceYes: insOne.instanceYes,
        instanceInfo: newInstanceInfo,
        instanceVar: insOne.instanceVar,
        student: insOne.student,
        distance: insOne.distance,
        sosSite: insOne.sosSite
    };
    ProcessHistoryModel.updateMany(where, newData, (err, doc) => { });

    ctx.body = result.go(result.code.CODE_200);
    return;
};

/**
 * 某一个保安已经到达报警地点阶段保存流程图和人物关系细节数据 - 以后所有的报警记录就可以自由的追溯
 * @param {*} ctx 
 * @param {*} next 
 */
let savaProcessAtReach = async (ctx, next) => {
    let instanceId = ctx.request.body.instanceId;
    let instanceInfo = ctx.request.body.data;
    let handleFigure = ctx.request.body.handleFigure;
    let taskType = ctx.request.body.taskType;

    let ProcessHistoryModel = await Model.getComModel({
        dataBase: 'com_info',
        tableName: 'process_history',
        schema: ProcessHistorySchema
    });

    //查询参与此流程的某个人
    let where = { instanceId: instanceId };
    let one = await new Promise((res, rej) => {
        ProcessHistoryModel
            .findOne(where)
            .exec((error, doc) => {
                return res(doc);
            });
    });
    if (!one.instanceInfo) {
        ctx.body = result.go(result.code.CODE_501);
        return;
    }

    //更新数据
    let oldInstanceInfo = one.instanceInfo;
    let vars = one.instanceVar;
    oldInstanceInfo['reach'] = {
        time: String(Date.now()),
        figure: instanceInfo
    };
    if (taskType == 'candidate') {
        //保安作为候选人来完成此任务的
        vars['handleFigure'] = handleFigure;
    }

    //更新
    let newData = {
        instanceInfo: oldInstanceInfo,
        instanceVar: vars,
    };
    ProcessHistoryModel.updateMany(where, newData, (err, res) => { });

    ctx.body = result.go(result.code.CODE_200);
    return;

};

/**
 * 保安处理完报警保存流程图和人物关系细节数据 - 以后所有的报警记录就可以自由的追溯
 */
let savaProcessAtOver = async (ctx, next) => {

    let instanceId = ctx.request.body.instanceId;
    let alarmRecord = ctx.request.body.alarmRecord;

    let ProcessHistoryModel = await Model.getComModel({
        dataBase: 'com_info',
        tableName: 'process_history',
        schema: ProcessHistorySchema
    });

    //查询参与此流程的某个人
    let where = { instanceId: instanceId };
    let one = await new Promise((res, rej) => {
        ProcessHistoryModel
            .findOne(where)
            .exec((error, doc) => {
                return res(doc);
            });
    });
    if (!one.instanceInfo) {
        ctx.body = result.go(result.code.CODE_501);
        return;
    }

    //更新数据
    let oldInstanceInfo = one.instanceInfo;
    let vars = one.instanceVar;
    let assignee = JSON.parse(JSON.stringify(oldInstanceInfo['reach']));
    assignee['time'] = String(Date.now());
    assignee['sosReason'] = alarmRecord;
    oldInstanceInfo['overAlarm'] = assignee;
    vars['alarmRecord'] = alarmRecord;

    //更新
    let newData = {
        instanceInfo: oldInstanceInfo,
        instanceVar: vars,
        $currentDate: {
            overTime: true
        },
        instanceYes: true
    };

    ProcessHistoryModel.updateMany(where, newData, (err, res) => { });

    ctx.body = result.go(result.code.CODE_200);
    return;

};

/**
 * 校徽报警 - 存某个组织的一堆候选队长分配任务数据细节
 */
let savaTissueLeader = async (ctx, next) => {

    let people = JSON.parse(ctx.request.body.people);
    let instanceInfo = JSON.parse(ctx.request.body.instanceInfo);

    let ProcessHistoryModel = await Model.getComModel({
        dataBase: 'com_info',
        tableName: 'process_history',
        schema: ProcessHistorySchema
    });

    let where = {
        instanceId: people[0].instanceId
    };

    //查询历史信息
    let insOne = await new Promise((res, rej) => {
        ProcessHistoryModel
            .findOne(where)
            .exec((error, doc) => {
                return res(doc);
            });
    });

    //先保存作为候选人的保安队长信息
    let peoLen = people.length - 1;
    await new Promise((res, rej) => {
        for (let key in people) {
            new ProcessHistoryModel(people[key]).save((error, doc) => {
                if (key == peoLen) {
                    return res();
                }
            });
        }
    });

    //同步所有数据
    let newInstanceInfo = insOne.instanceInfo;
    //分配任务阶段组装数据
    newInstanceInfo['candidateLeaders'] = {
        time: String(Date.now()),
        leaders: instanceInfo
    };
    let newData = {
        instanceInfo: newInstanceInfo,
        instanceVar: insOne.instanceVar,
        student: insOne.student,
        createTime: insOne.createTime,
        studentId: insOne.studentId,
        distance: insOne.distance,
        sosSite: insOne.sosSite
    };
    ProcessHistoryModel.updateMany(where, newData, (err, doc) => { });

    ctx.body = result.go(result.code.CODE_200);
    return;

};

/**
 * 校徽报警 - 存某个组织的队长分配任务已经完成存数据细节
 */
let saveInsOfGearTask = async (ctx, next) => {

    let gear = ctx.request.body.gear;
    let leader = ctx.request.body.leader;
    let handleFigure = ctx.request.body.handleFigure;

    let ProcessHistoryModel = await Model.getComModel({
        dataBase: 'com_info',
        tableName: 'process_history',
        schema: ProcessHistorySchema
    });

    let where = {
        instanceId: gear.instanceId
    };

    //查询历史信息
    let insOne = await new Promise((res, rej) => {
        ProcessHistoryModel
            .findOne(where)
            .exec((error, doc) => {
                return res(doc);
            });
    });

    //先保存实际去执行任务的保安信息
    await new Promise((res, rej) => {
        new ProcessHistoryModel(gear).save((error, doc) => {
            return res();
        });
    });

    //同步所有数据
    let newInstanceInfo = insOne.instanceInfo;
    //分配任务阶段组装数据
    newInstanceInfo['leaderComplate'] = {
        'time': String(Date.now()),
        'whoLeader': leader,
        'gear': {
            'peopleId': gear.peopleId,
            'name': gear.name,
            'peopleType': gear.peopleType
        }
    };
    let newVar = insOne.instanceVar;
    newVar['handleFigure'] = handleFigure;
    let newData = {
        createTime: insOne.createTime,
        schoolId: insOne.schoolId,
        studentId: insOne.studentId,
        instanceInfo: newInstanceInfo,
        instanceVar: newVar,
        student: insOne.student,
        distance: insOne.distance,
        sosSite: insOne.sosSite
    };
    ProcessHistoryModel.updateMany(where, newData, (err, doc) => { });

    ctx.body = result.go(result.code.CODE_200);
    return;

};

module.exports = {
    locationSave,
    getAll,
    getSosCandidate,
    saveProcess,
    getStudentLocation,
    saveProcessAtAssign,
    savaProcessAtReach,
    savaProcessAtOver,
    getLocationNNEmpty,
    getStuOrbit,
    savaTissueLeader,
    saveInsOfGearTask
}  